package jmine.tec.aom.domain;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import jmine.tec.persist.annotation.Alias;
import jmine.tec.persist.annotation.Comment;
import jmine.tec.persist.annotation.Constraint;
import jmine.tec.persist.annotation.DiscriminatorComment;
import jmine.tec.persist.annotation.Index;
import jmine.tec.persist.annotation.UniqueConstraint;
import jmine.tec.persist.annotation.UniqueConstraints;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Type;
import org.hibernate.validator.NotNull;

import bancosys.tec.component.Documentation;
import bancosys.tec.persist.bussobj.PersistableBusinessObject;
import bancosys.tec.persist.persister.annotation.SystemId;

/**
 * Defines a Property.
 * <p>
 * A Property is always associated to an existent {@link PropertyType}.
 * <p>
 * A Property defines a name and a mnemonic. The name will be used mainly on user interfaces to identify this Property (i.e. web page form).
 * The mnemonic will be used mainly by the system to interact with this Property (i.e. scripts).
 * 
 * @author jrenaut
 * @since 05/03/2007
 * @since 08/11/2011 - refactored to jMine TEC
 */
@Entity
@Alias("CARACT")
@Table(name = "CARACTERISTICAS")
@DiscriminatorValue(value = "0")
@DiscriminatorComment("PADRAO")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@SequenceGenerator(name = "SEQ_CARAC", sequenceName = "SEQ_CARAC")
@Constraint(suffix = "0")
@DiscriminatorColumn(name = "TP_CARACTERISTICA", discriminatorType = DiscriminatorType.INTEGER)
@UniqueConstraints({ @UniqueConstraint(name = "AK_CARACT_0", columns = { "COD_GRUPO_CARACTERISTICA", "MNE_CARAC" }),
        @UniqueConstraint(name = "AK_CARACT_1", columns = { "COD_GRUPO_CARACTERISTICA", "NOME" }) })
@Documentation("ARMAZENA AS CARACTERISTICAS DE PAPEIS, FLUXOS DE PAPEIS, TAXAS PATRIMONIAIS, MODELOS DE CALCULOS, PRODUTOS  E TRANSACOES DE PRODUTOS")
@Comment(table = "CARACTERISTICAS", column = "TP_CARACTERISTICA", value = "IDENTIFICA O TIPO DA CARACTERISTICA.")
public class Property extends PersistableBusinessObject {

    private Long id;

    private String name;

    private String mnemonic;

    private String description = "";

    private PropertyType propertyType;

    private PropertyGroup propertyGroup;

    /**
     * @return the id
     */
    @Id
    @SystemId
    @Column(name = "COD_CARACTERISTICA")
    @Documentation("CODIGO DA CARACTERISTICA")
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CARAC")
    public Long getId() {
        return this.id;
    }

    /**
     * @return the descricao
     */
    @Column(name = "DESCR", length = 4096)
    @Type(type = "org.hibernate.type.TextType")
    @Documentation("DESCRICAO DA CARACTERISTICA")
    public String getDescription() {
        return this.description;
    }

    /**
     * @return the user-friendly name
     */
    @NotNull
    @Column(name = "NOME", nullable = false)
    @Documentation("NOME DA CARACTERISTICA")
    public String getName() {
        return this.name;
    }

    /**
     * @return the system-friendly mnemonic
     */
    @NotNull
    @Column(name = "MNE_CARAC", nullable = false)
    @Documentation("MNEMONICO DA CARACTERISTICA")
    public String getMnemonic() {
        return this.mnemonic;
    }

    /**
     * @return the type
     */
    @NotNull
    @Index(suffix = "JT_1")
    @ManyToOne(optional = false)
    @JoinColumn(name = "COD_TIPO_CARAC", nullable = false)
    @Documentation("CÓDIGO DO TIPO DE CARACTERISTICA.")
    public PropertyType getPropertyType() {
        return this.propertyType;
    }

    /**
     * @return the {@link PropertyGroup}
     */
    @NotNull
    @Index(suffix = "JT_0")
    @ManyToOne(optional = false)
    @JoinColumn(name = "COD_GRUPO_CARACTERISTICA", nullable = false)
    @Documentation("CODIGO DO GRUPO DE CARACTERISTICA AO QUAL ESTA CARACTERISTICA PERTENCE")
    public PropertyGroup getPropertyGroup() {
        return this.propertyGroup;
    }

    /**
     * @param mnemonic the mnemonic to set
     */
    public void setMnemonic(String mnemonic) {
        this.mnemonic = mnemonic;
    }

    /**
     * @param description the description to set
     */
    public void setDescription(final String description) {
        this.description = description;
    }

    /**
     * @param name a user-friendly name
     */
    public void setName(final String name) {
        this.name = name;
    }

    /**
     * @param propertyType a {@link PropertyType}
     */
    public void setPropertyType(final PropertyType propertyType) {
        if (propertyType != null) {
            this.propertyType = propertyType;
        }
    }

    /**
     * @param id the id to set
     */
    public void setId(final Long id) {
        this.id = id;
    }

    /**
     * @param propertyGroup a {@link PropertyGroup}
     */
    public void setPropertyGroup(PropertyGroup propertyGroup) {
        this.propertyGroup = propertyGroup;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return String.format("[Caracteristica id=%d] %s", this.getId(), this.getName());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(this.mnemonic).toHashCode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }

        Class<?> thisClass = Hibernate.getClass(this);
        Class<?> otherClass = Hibernate.getClass(obj);

        if (thisClass != otherClass) {
            return false;
        }
        final Property other = (Property) obj;
        return new EqualsBuilder().append(this.mnemonic, other.getMnemonic()).isEquals();
    }

}
